package com.game.core.net.server;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.game.core.net.handler.AbstractMessageInitializer;


public class SimpleUdpServer
{
	private Bootstrap bootstrap;

	private static final Logger logger = LoggerFactory.getLogger(SimpleUdpServer.class);
	private Map<Integer, ChannelFuture> portMap = new HashMap<Integer, ChannelFuture>();
	SimpleUdpInitializer channelInitializer;
	AbstractMessageInitializer messageInitializer;
	
	public void initialize(ChannelInitializer<Channel> channelInitializer, AbstractMessageInitializer messageInitializer) throws Exception
	{
		if (channelInitializer instanceof SimpleUdpInitializer)
		{
			this.channelInitializer = (SimpleUdpInitializer) channelInitializer;
		}
		else
		{
			throw new IllegalArgumentException("channelInitializer is not instanceof simpleUdpInitializer ");
		}
		this.messageInitializer = messageInitializer;

		initializeNetty();
	};
	
	protected void initializeNetty()
	{
		EventLoopGroup workerGroup = new NioEventLoopGroup(32);
		bootstrap = new Bootstrap();
		bootstrap.group(workerGroup);
		bootstrap.channel(NioDatagramChannel.class);
		bootstrap.handler(channelInitializer);
	};

	public boolean openPort(InetSocketAddress localAddress)
	{
		if (bootstrap == null)
			throw new NullPointerException("serverBootstap");

		boolean result = false;
		try
		{
			ChannelFuture future = bootstrap.bind(localAddress);
			portMap.put(localAddress.getPort(), future);
			result = future.sync().isSuccess();
		}
		catch (Exception e)
		{
			result = false;
			logger.error("Failed to bind local address:{} InterruptedException err={}",localAddress,e.toString());
		}

		return result;
	}
	
	public int closePort(InetSocketAddress localAddress)
	{
		if(!portMap.containsKey(localAddress.getPort()))
			return -1;
		
		ChannelFuture future = portMap.get(localAddress.getPort());
		future.channel().close();
		return 0;
	}	
}
